/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "pin_auth_ipc_stub_inner.h"

#include <securec.h>
#include <stddef.h>

#include "pin_auth_core.h"

#include "logger.h"

ResultCode ProcPinAuthCmdGetNumSlotsStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataMaxSize < sizeof(uint32_t)) {
        LOG_ERROR("buffer is invalid");
        return INVALID_PARA_ERR_SIZE;
    }

    uint32_t numSlots = 0;
    ResultCode ret = ProcPinAuthCmdGetNumSlots(context->base.channel, &numSlots);
    if (ret != SUCCESS) {
        LOG_ERROR("ret is %u", ret);
        return ret;
    }

    *(uint32_t *)(buffer->data) = numSlots;
    buffer->dataSize = sizeof(uint32_t);
    return SUCCESS;
}

ResultCode ProcPinAuthCmdEnrollLocalStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(PinEnrollLocalInput)) {
        LOG_ERROR("buffer dataSize is not correct = %u", buffer->dataSize);
        return INVALID_PARA_ERR_SIZE;
    }

    if (buffer->dataMaxSize < sizeof(PinDataSecret)) {
        LOG_ERROR("buffer dataMaxSize is not correct = %u", buffer->dataMaxSize);
        return INVALID_PARA_ERR_SIZE;
    }

    const PinEnrollLocalInput *input = (const PinEnrollLocalInput *)buffer->data;
    PinDataSecret secret = {.data = {0}};

    ResultCode ret = ProcPinAuthCmdEnrollLocal(context->base.channel, input->slotId, &input->hash, &secret);
    if (ret != SUCCESS) {
        LOG_ERROR("ret is %u", ret);
        return ret;
    }

    if (memcpy_s(buffer->data, buffer->dataMaxSize, &secret, sizeof(PinDataSecret)) != EOK) {
        LOG_ERROR("memcpy_s error");
        return INVALID_PARA_ERR_SIZE;
    }

    buffer->dataSize = sizeof(PinDataSecret);
    return SUCCESS;
}

ResultCode ProcPinAuthCmdEnrollRemoteStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(PinEnrollRemoteInput)) {
        LOG_ERROR("buffer dataSize is not correct = %u", buffer->dataSize);
        return INVALID_PARA_ERR_SIZE;
    }

    const PinEnrollRemoteInput *input = (const PinEnrollRemoteInput *)buffer->data;

    ResultCode ret = ProcPinAuthCmdEnrollRemote(context->base.channel, input->slotId, &input->base);
    if (ret != SUCCESS) {
        LOG_ERROR("ret is %u", ret);
        return ret;
    }

    buffer->dataSize = 0;
    return SUCCESS;
}

ResultCode ProcPinAuthCmdAuthRemotePrepareStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(PinAuthRemotePrepareInput)) {
        LOG_ERROR("buffer dataSize is not correct = %u", buffer->dataSize);
        return INVALID_PARA_ERR_SIZE;
    }

    if (buffer->dataMaxSize < sizeof(PinDataRemoteServiceChallenge)) {
        LOG_ERROR("buffer dataMaxSize is not correct = %u", buffer->dataMaxSize);
        return INVALID_PARA_ERR_SIZE;
    }

    const PinAuthRemotePrepareInput *input = (const PinAuthRemotePrepareInput *)buffer->data;

    PinDataRemoteServiceChallenge output;
    (void)memset_s(&output, sizeof(output), 0, sizeof(output));

    ResultCode ret = ProcPinAuthCmdAuthRemotePrepare(context->base.channel, input->slotId, input->session, &output);
    if (ret != SUCCESS) {
        LOG_ERROR("ret is %u", ret);
        return ret;
    }

    if (memcpy_s(buffer->data, buffer->dataMaxSize, &output, sizeof(PinDataRemoteServiceChallenge)) != EOK) {
        LOG_ERROR("memcpy_s error");
        return INVALID_PARA_ERR_SIZE;
    }

    buffer->dataSize = sizeof(PinDataRemoteServiceChallenge);

    return SUCCESS;
}

ResultCode ProcPinAuthCmdAuthRemoteStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(PinAuthRemoteInput)) {
        LOG_ERROR("buffer dataSize is not correct = %u", buffer->dataSize);
        return INVALID_PARA_ERR_SIZE;
    }

    if (buffer->dataMaxSize < sizeof(PinAuthResult)) {
        LOG_ERROR("buffer dataMaxSize is not correct = %u", buffer->dataMaxSize);
        return INVALID_PARA_ERR_SIZE;
    }

    const PinAuthRemoteInput *input = (const PinAuthRemoteInput *)buffer->data;

    PinAuthResult output;
    (void)memset_s(&output, sizeof(output), 0, sizeof(output));

    ResultCode ret =
        ProcPinAuthCmdAuthRemote(context->base.channel, input->slotId, input->session, &input->proof, &output);
    if (ret != SUCCESS) {
        LOG_ERROR("ret is %u", ret);
        return ret;
    }

    if (memcpy_s(buffer->data, buffer->dataMaxSize, &output, sizeof(PinAuthResult)) != EOK) {
        LOG_ERROR("memcpy_s error");
        return INVALID_PARA_ERR_SIZE;
    }

    buffer->dataSize = sizeof(PinAuthResult);

    return SUCCESS;
}

ResultCode ProcPinAuthCmdAuthRemoteAbortStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(PinAuthRemoteAbortInput)) {
        LOG_ERROR("buffer dataSize is not correct = %u", buffer->dataSize);
        return INVALID_PARA_ERR_SIZE;
    }

    const PinAuthRemoteAbortInput *input = (const PinAuthRemoteAbortInput *)buffer->data;

    ResultCode ret = ProcPinAuthCmdAuthRemoteAbort(context->base.channel, input->slotId, input->session);
    if (ret != SUCCESS) {
        LOG_ERROR("ret is %u", ret);
        return ret;
    }

    buffer->dataSize = 0;
    return SUCCESS;
}

ResultCode ProcPinAuthCmdAuthLocalStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(PinAuthLocalInput)) {
        LOG_ERROR("buffer dataSize is not correct = %u", buffer->dataSize);
        return INVALID_PARA_ERR_SIZE;
    }

    if (buffer->dataMaxSize < sizeof(PinAuthResult)) {
        LOG_ERROR("buffer dataMaxSize is not correct = %u", buffer->dataMaxSize);
        return INVALID_PARA_ERR_SIZE;
    }

    const PinAuthLocalInput *input = (const PinAuthLocalInput *)buffer->data;

    PinAuthResult authResult = {.status = SE_PIN_AUTH_STATUS_FAIL};

    ResultCode ret = ProcPinAuthCmdAuthLocal(context->base.channel, input->slotId, &input->hash, &authResult);
    if (ret != SUCCESS) {
        LOG_ERROR("ret is %u", ret);
        return ret;
    }

    if (memcpy_s(buffer->data, buffer->dataMaxSize, &authResult, sizeof(PinAuthResult)) != EOK) {
        LOG_ERROR("memcpy_s error");
        return INVALID_PARA_ERR_SIZE;
    }

    buffer->dataSize = sizeof(PinAuthResult);
    return SUCCESS;
}

ResultCode ProcPinAuthCmdSetSelfDestructEnableStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(SetSelfDestructEnableInput)) {
        LOG_ERROR("buffer dataSize is not correct = %u", buffer->dataSize);
        return INVALID_PARA_ERR_SIZE;
    }

    if (buffer->dataMaxSize < sizeof(PinConfigResult)) {
        LOG_ERROR("buffer dataMaxSize is not correct = %u", buffer->dataMaxSize);
        return INVALID_PARA_ERR_SIZE;
    }

    const SetSelfDestructEnableInput *input = (const SetSelfDestructEnableInput *)buffer->data;
    PinDestructConfig config = {.destructMaxCnt = input->destructMaxCnt, .enable = input->enable};
    PinConfigResult configResult = {.status = SE_PIN_CONFIG_STATUS_FAIL_AUTH_ERR};

    ResultCode ret =
        ProcPinAuthCmdSetSelfDestructEnable(context->base.channel, input->slotId, &config, &input->hash, &configResult);
    if (ret != SUCCESS) {
        LOG_ERROR("ret is %u", ret);
        return ret;
    }

    if (memcpy_s(buffer->data, buffer->dataMaxSize, &configResult, sizeof(PinConfigResult)) != EOK) {
        LOG_ERROR("memcpy_s error");
        return INVALID_PARA_ERR_SIZE;
    }

    buffer->dataSize = sizeof(PinConfigResult);
    return SUCCESS;
}

ResultCode ProcPinAuthCmdGetFreezeStatusStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(uint32_t)) {
        LOG_ERROR("buffer dataSize is not correct = %u", buffer->dataSize);
        return INVALID_PARA_ERR_SIZE;
    }

    if (buffer->dataMaxSize < sizeof(PinFreezeStatus)) {
        LOG_ERROR("buffer dataMaxSize is not correct = %u", buffer->dataMaxSize);
        return INVALID_PARA_ERR_SIZE;
    }

    uint32_t slotId = *(uint32_t *)buffer->data;
    PinFreezeStatus pinFreezeStatus;
    ResultCode ret = ProcPinAuthCmdGetFreezeStatus(context->base.channel, slotId, &pinFreezeStatus);
    if (ret != SUCCESS) {
        LOG_ERROR("ret is %u", ret);
        return ret;
    }

    if (memcpy_s(buffer->data, buffer->dataMaxSize, &pinFreezeStatus, sizeof(PinFreezeStatus)) != EOK) {
        LOG_ERROR("memcpy_s error");
        return INVALID_PARA_ERR_SIZE;
    }

    buffer->dataSize = sizeof(PinFreezeStatus);
    return SUCCESS;
}

ResultCode ProcPinAuthCmdSetFreezePolicyStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(SetFreezePolicyInput)) {
        LOG_ERROR("buffer dataSize is not correct = %u", buffer->dataSize);
        return INVALID_PARA_ERR_SIZE;
    }

    SetFreezePolicyInput *input = (SetFreezePolicyInput *)buffer->data;

    buffer->dataSize = 0;
    return ProcPinAuthCmdSetFreezePolicy(context->base.channel, input->punishStartCnt, input->destructMaxCnt,
        input->enableDestructDefault);
}

ResultCode ProcPinAuthCmdGetFreezePolicyStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataMaxSize < sizeof(GetFreezePolicyOutput)) {
        LOG_ERROR("buffer dataMaxSize is not correct = %u", buffer->dataMaxSize);
        return INVALID_PARA_ERR_SIZE;
    }

    uint16_t punishStartCnt = 0;
    uint16_t destructMaxCnt = 0;
    uint32_t enableDestructDefault = 0;

    ResultCode ret =
        ProcPinAuthCmdGetFreezePolicy(context->base.channel, &punishStartCnt, &destructMaxCnt, &enableDestructDefault);
    if (ret != SUCCESS) {
        LOG_ERROR("ProcPinAuthCmdSetFreezePolicy is not success = %u", ret);
        return ret;
    }
    GetFreezePolicyOutput *output = (GetFreezePolicyOutput *)buffer->data;
    output->punishStartCnt = punishStartCnt;
    output->destructMaxCnt = destructMaxCnt;
    output->enableDestructDefault = enableDestructDefault;
    return SUCCESS;
}

ResultCode ProcPinAuthCmdEraseSingleSlotStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer == NULL || buffer->data == NULL) {
        LOG_ERROR("buffer is nullptr");
        return INVALID_PARA_NULL_PTR;
    }

    if (buffer->dataSize != sizeof(uint32_t)) {
        LOG_ERROR("buffer dataSize is not correct = %u", buffer->dataSize);
        return INVALID_PARA_ERR_SIZE;
    }
    uint32_t slotId = *(uint32_t *)buffer->data;

    return ProcPinAuthCmdEraseSingleSlot(context->base.channel, slotId);
}

ResultCode ProcPinAuthCmdEraseAllSlotsStub(PinAuthContext *context, SharedDataBuffer *buffer)
{
    (void)buffer;
    if (context == NULL) {
        LOG_ERROR("context is nullptr");
        return INVALID_PARA_NULL_PTR;
    }
    return ProcPinAuthCmdEraseAllSlot(context->base.channel);
}
